package com.itheima.stock.service.impl;

import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.stock.config.StockInfoConfig;
import com.itheima.stock.domain.*;
import com.itheima.stock.mapper.StockBlockRtInfoMapper;
import com.itheima.stock.mapper.StockBusinessMapper;
import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.mapper.StockRtInfoMapper;
import com.itheima.stock.pojo.StockBusiness;
import com.itheima.stock.service.StockService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.vo.resp.PageResult;
import com.itheima.stock.vo.resp.R;
import com.itheima.stock.vo.resp.ResponseCode;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StockServiceImpl implements StockService {
    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    @Override
    public List<StockBusiness> getAll() {
        return stockBusinessMapper.getAll();
    }

    /**
     * 获取最新国内A股大盘信息(上证+深证)
     *
     * @return
     */
    @Override
    public R<List<InnerMarketDomain>> getInnerMarketInfos() {
        //1.获取最近最新的一次股票交易有效时间点(精确分钟)
        Date lastDate4Stock = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();

        //临时指定一个假数据，因为限制还没做实时数据采集
        lastDate4Stock = DateTime.parse("2021-12-28 09:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.获取国内大盘的code码
        List<String> inner = stockInfoConfig.getInner();
        //3.调用mapper查询
        List<InnerMarketDomain> infos = stockMarketIndexInfoMapper.getInnerMarketInfosByCodesAndTime(lastDate4Stock,inner);
        //4.返回数据
        return R.ok(infos);
    }

    /**
     * 查询最新板块数据，按照交易金额降序取前10
     *
     * @return
     */
    @Override
    public R<List<StockBlockDomain>> getStockBlockInfos() {
        //1.获取最近最新的一次股票交易有效时间点(精确分钟)
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO mock数据,后续删除
        curDate=DateTime.parse("2021-12-21 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.获取板块数据
        List<StockBlockDomain> infos = stockBlockRtInfoMapper.getStockBlockInfos(curDate);
        return R.ok(infos);
    }

    /**
     * 沪深两市个股涨幅分时行情数据查询，以时间顺序和涨幅查询前10条数据
     * @return
     */
    @Override
    public R<List<StockUpdownDomain>> stockIncreaseLimit() {
        //1.直接调用mapper查询前10的数据 TODO 以时间顺序取前10
        //优化：
        //获取当前最近有效时间
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //mock数据
        String mockStr="2021-12-27 09:47:00";
        curDate=DateTime.parse(mockStr,DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //List<StockUpdownDomain> infos=stockRtInfoMapper.stockIncreaseLimit(curDateTime);
        //2.设置分页参数
        PageHelper.startPage(1,10);
        //3.查询
        List<StockUpdownDomain> infos = stockRtInfoMapper.getAllStockUpDownByTime(curDate);
        //2.判断是否有数据
        if (CollectionUtils.isEmpty(infos)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
        }
        return R.ok(infos);
    }

    /**
     * 分页查询股票涨幅信息
     * @param page 当前页
     * @param pageSize 每页大小
     * @return
     */
    @Override
    public R<PageResult<StockUpdownDomain>> getPageStockUpDownInfo(Integer page, Integer pageSize) {
        //1.获取最近最新的一次股票有效交易时间
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //mock数据
        String mockStr="2021-12-27 09:47:00";
        curDate=DateTime.parse(mockStr,DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //2.设置分页参数
        PageHelper.startPage(page,pageSize);
        //3.查询
        List<StockUpdownDomain> infos = stockRtInfoMapper.getAllStockUpDownByTime(curDate);
        //封装PageHelper分页对象
        PageInfo<StockUpdownDomain> pageInfo = new PageInfo<>(infos);
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(pageInfo);
        //封装结果返回
        return R.ok(pageResult);
    }

    /**
     * 功能描述：沪深两市涨跌停分时行情数据查询，查询T日每分钟的涨跌停数据（T：当前股票交易日）
     * 查询每分钟的涨停和跌停的数据的同级；
     * 如果不在股票的交易日内，那么就统计最近的股票交易下的数据
     * map:
     * upList:涨停数据统计
     * downList:跌停数据统计
     *
     * @return
     */
    @Override
    public R<Map> upDownCount() {
        //1.借助工具类获取最近交易日的开盘时间和收盘时间
        //获取有效时间点
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //根据有效的时间点获取对应日期的开盘和收盘日期
        Date openTime = DateTimeUtil.getOpenDate(endDateTime).toDate();
        Date closeTime = endDateTime.toDate();
        //TODO mock数据
        openTime= DateTime.parse("2022-01-06 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        closeTime= DateTime.parse("2022-01-06 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.查询涨停的统计数据
        List<Map> upList= stockRtInfoMapper.getStockUpDownCount(openTime,closeTime,1);
        //3.查询跌停的统计数据
        List<Map> downList= stockRtInfoMapper.getStockUpDownCount(openTime,closeTime,0);
        //4.组装map：将涨停和跌停的数据组装到map中
        HashMap<String, List> map = new HashMap<>();
        map.put("upList",upList);
        map.put("downList",downList);
        //5.返回结果
        return R.ok(map);
    }

    /**
     * 通过easyExcel导出指定页的股票涨幅信息
     *
     * @param response 通过响应对象获取输出流，完成excel文件流对象的输出
     * @param page     当前页
     * @param pageSize 每一页大小
     */
    @Override
    public void exportStockInfo(HttpServletResponse response, Integer page, Integer pageSize) {
        try {
            //设置响应数据的类型:excel
            response.setContentType("application/vnd.ms-excel");
            //设置响应数据的编码格式
            response.setCharacterEncoding("utf-8");
            //设置默认的文件名称
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("stockRt", "UTF-8");
            //设置默认文件名称
            response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");

            //1.获取最近最新的一次股票有效交易时间
            Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
            //mock数据
            String mockStr="2021-12-27 09:47:00";
            curDate=DateTime.parse(mockStr,DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

            //2.设置分页参数
            PageHelper.startPage(page,pageSize);
            //3.查询
            List<StockUpdownDomain> infos = stockRtInfoMapper.getAllStockUpDownByTime(curDate);
            //4.响应excel流
            EasyExcel
                    .write(response.getOutputStream(),StockUpdownDomain.class)
                    .sheet("股票信息")
                    .doWrite(infos);
        } catch (IOException e) {
            log.info("当前导出数据异常,当前页：{},每页大小：{},异常信息：{}",page,pageSize,e.getMessage());
        }
    }

    /**
     * 功能描述：统计国内A股大盘T日和T-1日成交量对比功能（成交量为沪市和深市成交量之和）
     * @return
     */
    @Override
    public R<Map<String, List>> getStockTradeVolCompare() {
        //1.获取T日交易时间范围
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date tEndDate = endDateTime.toDate();
        Date tStartDate = DateTimeUtil.getOpenDate(endDateTime).toDate();

        //TODO  mock数据
        tStartDate=DateTime.parse("2022-01-03 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        tEndDate=DateTime.parse("2022-01-03 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //2.根据T日获取T-1日的交易时间范围
        DateTime preEndDateTime = DateTimeUtil.getPreviousTradingDay(endDateTime);
        Date preEndDate = preEndDateTime.toDate();
        Date preStartDate = DateTimeUtil.getOpenDate(preEndDateTime).toDate();

        //TODO  mock数据
        preStartDate=DateTime.parse("2022-01-02 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        preEndDate=DateTime.parse("2022-01-02 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //3.获取大盘code编码集合
        List<String> inner = stockInfoConfig.getInner();

        //4.分布查询t日和t-1日的交易数据，组装
        List<Map> tData = stockMarketIndexInfoMapper.getAmountInfoByRangeTime(tStartDate,tEndDate,inner);
        List<Map> preData = stockMarketIndexInfoMapper.getAmountInfoByRangeTime(preStartDate,preEndDate,inner);

        //组装
        HashMap<String, List> mapInfo = new HashMap<>();
        mapInfo.put("volList",tData);
        mapInfo.put("yesVolList",preData);
        //5.返回指定格式的数据
        return R.ok(mapInfo);
    }

    /**
     * 统计当前有效时间点下各个涨跌区间的数量
     * @return
     */
    @Override
    public R<Map> getStockUpDownSection() {
        //1.获取股票最新一次交易的时候
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //mock data
        curDate = DateTime.parse("2022-01-06 09:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.查询股票信息
        List<Map> maps = stockRtInfoMapper.getStockUpDownSection(curDate);
        //2.1获取有序的标题集合
        List<String> upDownRange = stockInfoConfig.getUpDownRange();
        //思路：利用list集合的顺序性，然后循序遍历，找出哪个标题对应的map，然后维护到一个新的list集合下即可
        List<Map> orderMap = upDownRange.stream().map(key -> {
            Optional<Map> title = maps.stream().filter(map -> key.equals(map.get("title"))).findFirst();
            //判断对应的map是否存在
            Map tmp = null;
            if (title.isPresent()) {
                tmp = title.get();
            } else {
                tmp = new HashMap();
                tmp.put("title", key);
                tmp.put("count", 0);
            }
            return tmp;
        }).collect(Collectors.toList());

        //3.组装数据
        HashMap<String, Object> mapInfo = new HashMap<>();
        //获取指定日期格式的字符串
        String curDateStr = new DateTime(curDate).toString(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        mapInfo.put("time",curDateStr);
        mapInfo.put("infos",maps);
        //4.返回数据
        return R.ok(mapInfo);
    }

    /**
     * 查询股票的分钟级流水数据-->分时图展示需要
     * @param code
     * @return
     */
    @Override
    public R<List<Stock4MinuteDomain>> getStock4Minute(String code) {
        //1.获取最新股票交易时间点
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date startDate = DateTimeUtil.getOpenDate(endDateTime).toDate();
        Date endDate = endDateTime.toDate();
        //mock data
        endDate = DateTime.parse("2021-12-30 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        startDate = DateTime.parse("2021-12-30 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.查询指定日期范围内的数据
        List<Stock4MinuteDomain> infos = stockRtInfoMapper.getStock4Minute(startDate,endDate,code);
        //3.响应
        return R.ok(infos);
    }

    /**
     * 查询股票的日k线数据
     * @param code
     * @return
     */
    @Override
    public R<List<Stock4EvrDayDomain>> getStock4EvrDay(String code) {
        //1.获取最新股票交易时间点
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endDate = endDateTime.toDate();
        Date startDate = DateTimeUtil.getOpenDate(endDateTime.minusDays(10)).toDate();
        //mock data
        endDate = DateTime.parse("2021-01-06 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        startDate = DateTime.parse("2021-01-01 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper查询
        List<Stock4EvrDayDomain> infos = stockRtInfoMapper.getStock4EvrDay(startDate,endDate,code);
        //3.响应
        return R.ok(infos);
    }
}
